/**
 * 需安装 lodash
 */
import { isReactive } from 'vue'
import { cloneDeep } from 'lodash'

class ObjectUtils {
  static resetObject<T>(target: T, source: T) {
    for (const key in target) {
      const value = source[key]
      if (typeof value === 'object') {
        this.resetObject(target[key], source[key])
      } else {
        if (Object.prototype.hasOwnProperty.call(source, key)) {
          target[key] = source[key]
        }
      }
    }
  }
  /**
   * 深拷贝对象
   * @param obj - 要拷贝的对象
   */
  static cloneDeep<T>(obj: T): T {
    return cloneDeep(obj)
  }

  /**
   * 判断对象是否为空
   * @param {Object} obj - 要判断的对象
   * @returns {boolean} 是否为空
   */
  static isEmpty(obj?: object): boolean {
    return (
      obj === null ||
      obj === undefined ||
      (Object.keys(obj).length === 0 && obj.constructor === Object)
    )
  }

  /**
   * 深拷贝对象
   * @param {Object} obj - 要拷贝的对象
   * @returns {Object} 深拷贝后的对象
   */
  static deepClone<T>(obj: T): T {
    return JSON.parse(JSON.stringify(obj))
  }

  static copy<T>(obj: any, type: T): T {
    const clone = {} as T
    // 遍历 type 的键，确保只拷贝 type 中定义的属性
    for (const key in type) {
      if (
        Object.prototype.hasOwnProperty.call(type, key) &&
        Object.prototype.hasOwnProperty.call(obj, key)
      ) {
        const value = obj[key]
        // 如果属性也是对象，递归深拷贝
        if (typeof value === 'object' && value !== null) {
          clone[key] = this.copy(value, type[key] as any) // 使用 as any 解决类型不匹配
        } else {
          clone[key] = value as T[Extract<keyof T, string>] // 确保 clone[key] 的类型兼容
        }
      }
    }
    return clone
  }

  /**
   * 动态添加响应式属性到对象
   * @param target 目标对象
   * @param property 属性名
   * @param value 属性值
   */
  static setReactiveProperty<T extends object>(target: T, property: string, value: any): void {
    if (isReactive(target)) {
      ;(target as Record<string, any>)[property] = value
    } else {
      console.warn('Target is not reactive')
    }
  }

  /**
   * 合并多个对象
   * @param {...Object} sources - 要合并的对象
   * @returns {Object} 合并后的对象
   */
  static merge(...sources: Array<object>): object {
    return Object.assign({}, ...sources)
  }

  /**
   * 判断两个对象是否相等
   * @param {Object} obj1 - 第一个对象
   * @param {Object} obj2 - 第二个对象
   * @returns {boolean} 是否相等
   */
  static equals(obj1: object, obj2: object): boolean {
    return JSON.stringify(obj1) === JSON.stringify(obj2)
  }

  /**
   * 获取对象的所有键
   * @param {Object} obj - 对象
   * @returns {Array} 对象的键数组
   */
  static keys(obj: object): Array<any> {
    return Object.keys(obj)
  }

  /**
   * 获取对象的所有值
   * @param {Object} obj - 对象
   * @returns {Array} 对象的值数组
   */
  static values(obj: object): Array<any> {
    return Object.values(obj)
  }

  /**
   * 将对象转换为查询字符串
   * @param {Object} obj - 要转换的对象
   * @returns {string} 查询字符串
   */
  static toQueryString(obj: object): string {
    return Object.entries(obj)
      .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
      .join('&')
  }

  /**
   * 从对象中移除指定的属性
   * @param {Object} obj - 对象
   * @param {...string} keys - 要移除的属性名
   * @returns {Object} 移除属性后的对象
   */
  static omit<T extends Record<string, any>>(obj: T, ...keys: Array<keyof T>): Partial<T> {
    const result: Partial<T> = { ...obj }
    keys.forEach((key) => {
      delete result[key]
    })
    return result
  }

  /**
   * 获取对象的嵌套属性值
   * @param {Object} obj - 对象
   * @param {string} path - 属性路径（如 "a.b.c"）
   * @returns {*} 嵌套属性的值
   */
  static get<T extends Record<string, any>>(obj: T, path: string): any {
    return path.split('.').reduce((acc, key) => (acc ? acc[key] : undefined), obj)
  }

  /**
   * 设置对象的嵌套属性值
   * @param {Record<string, any>} obj - 对象
   * @param {string} path - 属性路径（如 "a.b.c"）
   * @param {*} value - 要设置的值
   * @returns {Record<string, any>} 设置属性后的对象
   */
  static set<T extends Record<string, any>>(obj: T, path: string, value: any): T {
    const keys: string[] = path.split('.')
    let current: Record<string, any> = obj

    keys.forEach((key: string, index: number) => {
      if (index === keys.length - 1) {
        current[key] = value // 设置值
      } else {
        if (!current[key]) {
          current[key] = {} // 初始化嵌套对象
        }
        current = current[key] // 进入下一层
      }
    })
    return obj // 返回修改后的对象
  }

  /**
   * 清空对象的属性值
   * @param {Object} obj - 要清空属性值的对象
   * @returns {Object} 清空属性值后的对象
   */
  static clearProperties(obj: Record<string, any>): object {
    for (const key in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        if (typeof obj[key] === 'string') {
          obj[key] = ''
        } else if (typeof obj[key] === 'number') {
          obj[key] = 0
        } else if (typeof obj[key] === 'boolean') {
          obj[key] = false
        } else if (Array.isArray(obj[key])) {
          obj[key] = []
        } else if (obj[key] && typeof obj[key] === 'object') {
          this.clearProperties(obj[key]) // 递归清空嵌套对象
        }
      }
    }
    return obj
  }
}

export default ObjectUtils
